package com.jwater.core.net.group.data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwater.core.common.S;

import jwater.org.apache.commons.io.IOUtils;

/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class DurableData {
    protected static Logger logger = LoggerFactory.getLogger(DurableData.class);
    public static final String SPLIT_STR = "#";

    private boolean isUpdate = false;
    private Map<String, DurableDataItem> items = new ConcurrentHashMap<>(32);

    public Map<String, DurableDataItem> items() {
        return items;
    }

    /**
     * 通过前缀获取
     *
     * @param key
     * @param prefix
     * @return
     */
    public Map<String, DurableDataItem> getItemsByPrefix(String key, String prefix) {
        Map<String, DurableDataItem> map = new HashMap<String, DurableDataItem>();
        for (Entry<String, DurableDataItem> en : items.entrySet()) {
            if (en.getKey().startsWith(prefix)) {
                map.put(en.getKey(), en.getValue());
            }
        }
        return map;
    }

    /**
     * @param itemKey
     * @return
     */
    public DurableDataItem getItem(String itemKey) {
        return items.get(itemKey);
    }

    public void setUpdate(boolean isUpdate) {
        this.isUpdate = isUpdate;
    }

    public boolean getUpdate() {
        return isUpdate;
    }

    /**
     * @param itemKey
     * @param version
     * @param data
     */
    public void setItem(String itemKey, long version, String data) {
        DurableDataItem item = items.get(itemKey);
        if (item == null) {
            item = new DurableDataItem();
            item.setVersion(version);
            item.setData(data);
            items.put(itemKey, item);
            isUpdate = true;
        } else {
            if (version > item.getVersion()) {
                item.setVersion(version);
                item.setData(data);
                isUpdate = true;
            }
        }
    }

    public void removeItem(String itemKey) {
        isUpdate = true;
        items.remove(itemKey);
    }

    /**
     * 存储到本地文件
     *
     * @param path
     * @param fileName
     */
    public void store(String path, String fileName) {
        //logger.info("durable store to file," + path + "," + fileName);
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            PrintStream ps = new PrintStream(new FileOutputStream(path + fileName), false, S.charset);
            for (Entry<String, DurableDataItem> en : items.entrySet()) {
                String value = en.getKey() + SPLIT_STR + en.getValue().getVersion() + SPLIT_STR
                        + en.getValue().getData();
                //logger.info("store:" + value);
                ps.println(value);
            }
            ps.close();
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
    }

    /**
     * 从本地文件加载
     *
     * @param path
     * @param fileName
     */
    public void load(String path, String fileName) {
        try {
            FileInputStream fis = new FileInputStream(path + fileName);
            List<String> lines = IOUtils.readLines(fis, S.charset);
            for (String line : lines) {
                try {
                    int index1 = line.indexOf(SPLIT_STR);
                    int index2 = line.indexOf(SPLIT_STR, index1 + 2);
                    String key = line.substring(0, index1);
                    String version = line.substring(index1 + 1, index2);
                    String data = line.substring(index2 + 1);
                    //logger.info("key:" + key + ",version:" + version + ",data:" + data);
                    DurableDataItem item = new DurableDataItem();
                    item.setVersion(Long.parseLong(version));
                    item.setData(data);
                    items.put(key, item);
                } catch (Exception e) {
                    logger.warn(e.toString() + ",load error for:" + line);
                }
            }
            fis.close();
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
    }
}
